package com.guosheng.test20181214;

import com.alibaba.fastjson.JSON;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

public class BeanUtil {

    /**
     * 该方法针对的是来源类和目标类有相同的属性名
     * @param srcBean
     * @param tarBean
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void copyBeanProperties(Object srcBean,Object tarBean) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        //实现Bean属性的复制功能 introspector汉语意思是内省
        /*
        Introspector.getBeanInfo();
        在javaBean上进行内省，了解其所有属性，公开的方法和事件
         */
        BeanInfo srcInfo = Introspector.getBeanInfo(srcBean.getClass());
        BeanInfo tarInfo = Introspector.getBeanInfo(tarBean.getClass());
        //将目标的bean写出方法保存在散列表，用于优化查找
        HashMap<String, Method> map = new HashMap<>();
        //获得beans PropertyDescriptor 描述java bean 通过一对存储器方法导出的一个属性
        PropertyDescriptor[] descriptorSrc = tarInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd:descriptorSrc) {
            String name = pd.getName();//获得此特性的编程名称，有点抽象了
            Method method = pd.getWriteMethod();//获得应该用于写入属性值的方法
            if(null != method){
                map.put(name,method);
            }
        }
        System.out.println("########################"+JSON.toJSONString(map));
        //迭代每个srcBean的属性
        PropertyDescriptor[] descriptorTar = srcInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd:descriptorTar) {
            String name = pd.getName();
            Method getMethod = pd.getReadMethod();
            Method setMethod = map.get(name);
            if(null != getMethod && null != setMethod){
                //执行srcBean的get方法获取值
                Object val = getMethod.invoke(srcBean);
                //执行tarBean的set方法设置值
                setMethod.invoke(tarBean,val);
            }
        }

        System.out.println("Bean属性复制完毕！");
        Introspector.flushCaches();
    }

    /**
     * 该方法拷贝的是来源属性名和目标属性名不同：
     * 解决的模式为：xxx_yyy ->xxxYyy 或者 xxxYyy - > xxx_yyy
     * flag 为1时，来源属性名为xxx_yyy目标属性名为xxxYyy
     * flag 为0时，来源属性名为xxxYyy目标属性名为xxx_yyy
     * flag为null时，则来源和目标属性名相同
     * @param src
     * @param target
     */
    public static void copyPropertiesWithTuoFeng(Object src,Object target,Integer flag) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        BeanInfo srcInfo = Introspector.getBeanInfo(src.getClass());
        BeanInfo tarInfo = Introspector.getBeanInfo(target.getClass());
        HashMap<String,Method> map = new HashMap<>();
        PropertyDescriptor[] pdsrcs = srcInfo.getPropertyDescriptors();
        for(PropertyDescriptor pd:pdsrcs){
            String name = pd.getName();

            Method method = pd.getReadMethod();
            if(null != method){
                if(null == flag){
                    map.put(name,method);
                }else if(flag == 1){//来源属性名为xxx_yyy目标属性名为xxxYyy
                    map.put(xxx_yyyToxxxYyy(name),method);
                }else if(flag == 0){//来源属性名为xxxYyy目标属性名为xxx_yyy
                    map.put(xxxYyy2xxx_yyy(name),method);
                }
            }
        }

        PropertyDescriptor[] pdtars = tarInfo.getPropertyDescriptors();
        for(PropertyDescriptor pd : pdtars){
            String name = pd.getName();
            Method setMethod = pd.getWriteMethod();
            Method getMethod = map.get(name);
            if(null != getMethod && null != setMethod){
                Object val = (Object) getMethod.invoke(src);
                setMethod.invoke(target,val);
            }
        }
        System.out.println("拷贝结束，执行成功！");
        Introspector.flushCaches();
    }

    /**
     * 将xxx_yyy类型的字符串转换成xxxYyy
     * @param xxx_yyy
     * @return
     */
    public static String xxx_yyyToxxxYyy(String xxx_yyy){
        if(null != xxx_yyy && !xxx_yyy.trim().equals("")){
            StringBuilder convert = new StringBuilder();
            String[] strs = xxx_yyy.split("_");
            convert.append(strs[0]);
            for (int i=1;i<strs.length;i++) {
                convert.append(strs[i].substring(0,1).toUpperCase());
                convert.append(strs[i].substring(1));
            }
            return convert.toString();
        }
        return xxx_yyy;
    }


    /**
     * 将xxxYyy类字符串转换成xxx_yyy类型
     * @param xxxYyy
     * @return
     */
    public static String xxxYyy2xxx_yyy(String xxxYyy){
        if(null != xxxYyy && !xxxYyy.trim().equals("")){
            StringBuilder sb = new StringBuilder();
            char[] charArray = xxxYyy.toCharArray();
            char xiahuaxian = '_';
            for(int i=0;i<charArray.length;i++){
                if(charArray[i] >= 'A' && charArray[i] <= 'Z'){
                    sb.append(xiahuaxian);
                    sb.append(charArray[i]);
                }else{
                    sb.append(charArray[i]);
                }
            }
            return sb.toString().toLowerCase();
        }
        return xxxYyy;
    }

}
